%%%--------------------------------------------
%%% @author Smallk
%%% @copyright 2021-2023 ml
%%% @doc A rpc server based on tcp
%%% @end
%%% ------------------------------------------- 

-module(tr_server).
%% -compile(export_all).
-include_lib("eunit/include/eunit.hrl").
-behaviour(gen_server).

%% API
-export([start_link/1, start_link/0, get_count/0, stop/0]).

%% gen_server callback
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
        terminate/2, code_change/3]).

-define(SERVER, ?MODULE).
-define(DEFAULT_PORT, 5587).

-record(state, {
    port,                       % 端口
    lsock,                      % 监听套剪子
    request_count = 0           % 请求连接的数量 
    }).


%%%===========================================================
%%%API
%%%===========================================================


%%%--------------------------------------------
%%% @doc Starts the server
%%% 
%%% @spec start_link(Port::integer()) -> {ok, Pid}
%%% where 
%%%     Pid = pid()
%%% @end
%%% ------------------------------------------- 
start_link(Port) ->
    gen_server:start_link({local, ?SERVER}, ?MODULE, [Port], []).
%% @doc Calls `start_link(Port)` using the default port
%% @spec start_link() -> {ok, Pid}
%% @end
start_link() ->
    start_link(?DEFAULT_PORT).

%%%--------------------------------------------
%%% @doc Fetches the number of hosts connecting to the server
%%%
%%% @spec get_count() -> {ok, Count}
%%% where 
%%%     Count = integer()
%%% @end
%%% ------------------------------------------- 
get_count() ->
    gen_server:call(?SERVER, get_count).

%%%--------------------------------------------
%%% @doc Stops the server
%%% @spec stop() -> ok
%%% @end
%%% ------------------------------------------- 
stop() ->
    gen_server:cast(?SERVER, stop).


%%%===========================================================
%%%Callbacks
%%%===========================================================
init([Port]) ->
    {ok, LSock} = gen_tcp:listen(Port, [{active, true}, {reuseaddr, true}]),
    {ok, #state{port = Port, lsock = LSock}, 0}.

%% 处理同步请求
handle_call(get_count, _From, State) ->
    {reply, {ok, State#state.request_count}, State};

handle_call(Info, _From, State) ->
    io:format("Err: ~p~n", [Info]),
    {reply, {no, 0}, State}.

%% 处理异步请求消息
handle_cast(stop, State) ->
    {stop, normal, State}.

handle_info({tcp, Socket, RawData}, State) ->
    do_rpc(Socket, RawData),
    RequestCount = State#state.request_count,
    {noreply, State#state{request_count = RequestCount + 1}};
handle_info(timeout, #state{lsock = LSock} = State) ->
    {ok, _Sock} = gen_tcp:accept(LSock),
    {noreply, State}.

terminate(_Resason, _State) -> ok.
code_change(_OldVsn, State, _Extra) -> {ok, State}.



%%%===========================================================
%%%Internal functions
%%%===========================================================

do_rpc(Socket, RawData) ->
    try
        {M, F, A} = split_out_mfa(RawData),
        io:format("M: ~p~n, F: ~p~n, A: ~p~n", [M,F,A]),
        Result = apply(M, F, A),
        gen_tcp:send(Socket, io_lib:fwrite("~p~n", [Result]))
    catch 
        _Class:Err ->
            gen_tcp:send(Socket, io_lib:fwrite("~p~n", [Err]))
    end.

split_out_mfa(RawData) ->
    MFA = re:replace(RawData, "\r\n$", "", [{return, list}]),
    {match, [M, F, A]} = 
        re:run(MFA, "(.*):(.*)\s*\\(\s*(.*)\s*\\)\s*\\.\s*$", [{capture, [1,2,3], list}, ungreedy]),
    {list_to_atom(M), list_to_atom(F), split_args_to_list(A)}.

split_args_to_list(RawArgs) ->
    {ok, Toks, _Line} = erl_scan:string("[" ++ RawArgs ++ "]."),
    {ok, Args} = erl_parse:parse_term(Toks),
    Args. 


%%%===========================================================
%%% Test function
%%%===========================================================
start_test() ->
    {ok, _} = start_link(1155).
